EP7. 모델튜닝 — SFT, RLHF, DPO
사전학습된 LLM의 파라미터를 목적에 맞게 미세 조정하는 세 기법(SFT·RLHF·DPO)의 원리·데이터·손실 함수를 비교하고, instruction-following 능력과 선호도 정렬(alignment)을 달성하는 방법을 정리합니다.
0. 사전 필수 용어 (선행지식)
사전학습 (Pre-training) 수십억~수조 개 토큰 데이터로 언어 모델의 파라미터를 초기화하는 과정입니다. 다음 토큰 예측 손실(next-token prediction loss)로 학습합니다. 비유: 시험을 위한 교과서 전체 독파. → §1 "주제 정의" 및 §3 "핵심 개념" 전반에서 참조.
손실 함수 (Loss Function) 모델 예측과 정답 간 오차를 수치화하는 함수로, 역전파(backpropagation)의 기준이 됩니다. SFT는 교사 강제(teacher forcing) CE loss, DPO는 선호도 대비 손실을 사용합니다. → §6 "핵심 원리"에서 구체적으로 다룸.
로그 확률 (Log Probability, logprob) 시퀀스 전체가 생성될 확률을 토큰별 소프트맥스 확률값의 로그 합으로 계산한 단일 스칼라입니다. 비유: 문장 전체의 신뢰도 점수. → §3 RLHF 메커니즘, §6 원리에서 핵심 개념.
LoRA / QLoRA Low-Rank Adaptation: 모델 전체 재학습 대신 소규모 저랭크(low-rank) 행렬 두 개를 추가하여 학습하는 PEFT 기법입니다. QLoRA는 4-bit 양자화를 결합해 소비자 GPU에서도 실행됩니다. 비유: 교과서에 포스트잇 메모만 추가하는 방식. → §3·§4·§7에서 핵심 구현 경량화 방법으로 사용.
PPO (Proximal Policy Optimization) RLHF에서 보상값이 급격히 커지는 현상(보상 해킹)을 방지하는 강화 학습 알고리즘입니다. 정책 변화량에 클리핑(clipping) 제약을 두어 안정적 학습을 유도합니다. → §3 RLHF 메커니즘, §9 한계에서 reward hacking과 함께 등장.
📚 참고 — Andrej Karpathy "State of GPT" (https://youtu.be/bZQun8Y4L2A) 에서 SFT→RLHF 파이프라인을 시각적으로 설명합니다.
1. 주제 정의
모델튜닝(SFT / RLHF / DPO)은 사전학습된 LLM의 출력을 원하는 방향으로 조정하는 사후 학습(post-training) 기법으로, 지시 이행성(instruction-following ability)과 인간 선호도 정렬(alignment)을 목표로 합니다.
핵심 아이디어: 사전학습이 "언어를 배우는 단계"라면, 사후 학습 튜닝은 "어떤 방향으로 말할지를 조정하는 단계"입니다.
2. 풀려는 문제
- 문제 1 — Base 모델의 instruction-following 부재: 사전학습만 된 모델은 질문에 대해 다음 토큰을 예측할 뿐, 사용자의 지시에 따라 응답 방향을 바꾸지 못합니다. SFT가 이를 해결합니다.
- 문제 2 — 시스템 프롬프트 무효화: instruction 없는 SFT 학습 모델은 시스템 프롬프트 지시가 유저 프롬프트와 거의 차이 없이 처리됩니다.
- 문제 3 — 인간 선호도와의 괴리: 문법적으로 옳지만 유해하거나 불성실한 답변을 생성하는 문제를 RLHF/DPO가 해결합니다.
- 문제 4 — 보상 모델 구축 비용: RLHF는 별도 보상 모델(reward model) 학습이 필요해 비용·복잡도가 높습니다. DPO가 이를 제거합니다.
💡 실무 노하우 — 프로덕션에서는 SFT 없이 RLHF/DPO를 적용하면 안 됩니다. SFT가 instruction 분포를 먼저 학습해야 선호도 튜닝이 유효합니다.
3. 핵심 개념·구조
SFT (Supervised Fine-Tuning)
- 데이터:
{"instruction": "...", "input": "...", "output": "..."}형태의 정답 전용 데이터셋 - 학습 방식: 질문(instruction + input) 부분은 기존 모델 가중치로 어텐션 계산, 답변 토큰 생성 부분만 손실 함수에 반영
- 핵심 효과: instruction이 모델의 시스템 프롬프트로 작동 → 다양한 instruction 하에 동일 질문의 답변 방향이 달라지도록 학습
RLHF (Reinforcement Learning from Human Feedback)
- 데이터:
{"prompt": "...", "response_1": "...", "response_2": "...", "preferred": 1}— 인간이 선호도 레이블 부여 - 학습 방식: 선택된 답변 시퀀스의 로그 확률(logprob)에 보상값(reward)을 곱해 손실 함수 구성 → 역전파
- 보상 반영 위치: 주로 마지막 어텐션 레이어의 FFN(Feed Forward Network), 일부 어텐션 가중치
- PPO로 보상값 폭주 방지
DPO (Direct Preference Optimization)
- 데이터:
{"prompt": "...", "chosen": "...", "rejected": "..."}— 선택/거부 쌍 - 학습 방식: 보상 모델 없이 chosen·rejected 두 시퀀스의 로그 확률 차이를 직접 손실로 사용
- 목표: 차이를 최대화 → chosen 확률 ↑, rejected 확률 ↓
SFT 파이프라인
──────────────────────────────────────────
사전학습 Base 모델
│
▼ instruction+input+output 데이터
SFT 학습 (답변 토큰만 CE loss)
│
▼
Instruction-Following 모델
RLHF 파이프라인
──────────────────────────────────────────
SFT 모델
│
▼ (prompt, chosen, rejected) + 인간 선호 레이블
보상 모델(Reward Model) 학습
│
▼ PPO + 보상 신호
정책 모델(Policy Model) 업데이트
│
▼
선호도 정렬 모델
DPO 파이프라인
──────────────────────────────────────────
SFT 모델
│
▼ (prompt, chosen, rejected) 쌍
logprob(chosen) - logprob(rejected) 차이 최대화
│
▼
선호도 정렬 모델 (보상 모델 불필요)
4. 구현 가이드 (Do It Yourself)
시작 전 (Before you begin)
본 섹션 완료 시 SFT·DPO 학습 루프를 로컬 GPU 환경에서 실행할 수 있습니다.
선수 조건:
- Python 3.10+
- pip install transformers trl datasets peft accelerate bitsandbytes
- HuggingFace 토큰 (HF_TOKEN) — 환경 변수
- GPU (최소 VRAM 8GB, QLoRA 사용 시)
소요 시간: 약 30~60분 (GPU 의존).
Step 1 — 데이터 준비 (SFT instruction dataset)
목표: instruction-input-output 3열 데이터셋 로드.
from datasets import load_dataset
dataset = load_dataset("tatsu-lab/alpaca", split="train")
이 코드는 HuggingFace Hub에서 공개된 Alpaca instruction 데이터셋을 로드합니다. instruction·input·output 컬럼이 포함되어 있습니다.
⚠️ 주의 —
HF_TOKEN환경 변수가 없으면 gated 모델 접근이 거부됩니다.huggingface-cli login으로 사전 인증하세요.💡 실무 노하우 — 데이터 품질이 양보다 중요합니다. 10만 건의 노이즈 데이터보다 1만 건의 고품질 instruction 쌍이 SFT 성능을 더 높입니다.
📚 참고 — HuggingFace Datasets (https://huggingface.co/docs/datasets)
✅ 확인:
print(dataset[0])실행 시instruction·input·output키가 출력됩니다.
Step 2 — SFT 학습 (SFTTrainer)
목표: TRL의 SFTTrainer로 instruction-following 모델 학습.
from trl import SFTTrainer, SFTConfig
from transformers import AutoModelForCausalLM, AutoTokenizer
model = AutoModelForCausalLM.from_pretrained("Qwen/Qwen2-0.5B")
trainer = SFTTrainer(model=model, args=SFTConfig(output_dir="sft-out"),
train_dataset=dataset)
trainer.train()
SFTTrainer는 내부적으로 답변 토큰 부분만 손실 함수에 반영하고, instruction 부분은 마스킹합니다.
⚠️ 주의 — GPU VRAM 부족 시
load_in_4bit=True(QLoRA)를 사용하세요.bitsandbytes설치 필수.💡 실무 노하우 —
gradient_checkpointing=True설정으로 VRAM 사용량을 30~50% 줄일 수 있습니다.📚 참고 — HuggingFace TRL SFTTrainer (https://huggingface.co/docs/trl/sft_trainer)
✅ 확인: 학습 로그에
loss값이 단계별로 감소하면 정상입니다.
Step 3 — DPO 학습 (preference dataset + DPOTrainer)
목표: chosen/rejected 쌍 데이터로 선호도 정렬.
from trl import DPOTrainer, DPOConfig
trainer = DPOTrainer(model=sft_model, ref_model=ref_model,
args=DPOConfig(beta=0.1, output_dir="dpo-out"),
train_dataset=pref_dataset)
trainer.train()
beta=0.1은 KL 정규화 강도입니다. 값이 클수록 reference 모델에서 멀리 벗어나지 않게 제한됩니다.
⚠️ 주의 —
ref_model은 SFT 완료 모델의 고정(frozen) 복사본입니다. 메모리가 2배 필요합니다.💡 실무 노하우 —
beta값은 0.05~0.5 범위에서 실험하세요. 너무 낮으면 chosen/rejected 구분이 무너지고, 너무 높으면 학습이 정체됩니다.📚 참고 — DPO 원논문 (https://arxiv.org/abs/2305.18290)
✅ 확인:
rewards/chosen이rewards/rejected보다 높게 유지되면 학습 방향이 정상입니다.
Step 4 — 평가 (eval loop)
목표: 학습된 모델의 instruction-following 품질 검증.
from transformers import pipeline
pipe = pipeline("text-generation", model="./sft-out")
print(pipe("Translate the following phrase into French: I love you")[0]["generated_text"])
✅ 확인: instruction에 맞는 출력("Je t'aime" 등)이 생성됩니다.
Step 5 — 동작 확인
SFT 학습 후 동일 입력에 instruction을 바꾸면 출력이 달라지는 것을 확인합니다.
입력: "I love you"
instruction="Translate the following phrase into French" → "Je t'aime"
instruction="Translate the following phrase into Korean" → "사랑해"
5. 적용 사례 (공신력 오픈소스 5가지+)
- HuggingFace TRL (https://github.com/huggingface/trl) —
SFTTrainer·DPOTrainer·PPOTrainer통합 API. 현재 SFT/RLHF/DPO 표준 구현체로,DPOTrainer의beta파라미터로 KL 정규화를 직접 조정합니다. - HuggingFace Transformers (https://github.com/huggingface/transformers) —
AutoModelForCausalLM·AutoTokenizer·Trainer. 모든 모델 로드·토크나이저 처리의 기반. - HuggingFace PEFT (https://github.com/huggingface/peft) — LoRA·QLoRA 구현. RLHF 보상 반영 위치(마지막 FFN)에 경량 레이어를 추가하는 표준 방법.
- LLaMA-Factory (https://github.com/hiyouga/LLaMA-Factory) — YAML 설정 한 파일로 SFT/RLHF/DPO/ORPO를 선택·실행하는 통합 CLI. 다국어 instruction 데이터셋 150+ 내장.
- Axolotl (https://github.com/OpenAccess-AI-Collective/axolotl) — YAML 기반 fine-tuning 프레임워크. Flash Attention 2·NEFTune·packed sequences 등 학습 최적화를 설정 파일로 제어합니다.
- vLLM (https://github.com/vllm-project/vllm) — fine-tuned 모델 inference 서빙. PagedAttention으로 VRAM 효율을 높이며 OpenAI-compatible API 제공.
- Anthropic Python SDK (https://github.com/anthropics/anthropic-sdk-python) — RLHF 결과물인 Claude API 활용.
model="claude-opus-4-7",model="claude-sonnet-4-6",model="claude-haiku-4-5-20251001"세 모델 중 선택. - DeepSpeed (https://github.com/microsoft/DeepSpeed) — ZeRO-3 메모리 최적화로 RLHF 전체 학습 가능. 소비자 GPU 다중 구성에서 70B 모델 학습에 활용.
📚 참고 — 위 OSS들은 모두 GitHub stars 5K+ 또는 Anthropic·HuggingFace·Microsoft 공식 SDK/프레임워크입니다.
6. 핵심 원리
SFT 손실 함수
답변 토큰 부분만 Cross-Entropy Loss를 적용합니다. instruction과 input은 마스킹되어 그래디언트가 흐르지 않습니다. 같은 질문에 instruction이 다르면 다른 CE 타겟이 되어, 모델이 instruction 조건부 출력을 학습합니다.
L_SFT = -Σ log P(y_t | y_{<t}, x) [y = 답변 토큰만]
DPO 손실 함수
보상 모델 없이 직접 선호도를 손실로 변환합니다. chosen 시퀀스 logprob과 rejected 시퀀스 logprob의 차이에 sigmoid를 적용합니다.
L_DPO = -log σ(β · (log π(y_w|x)/π_ref(y_w|x)
- log π(y_l|x)/π_ref(y_l|x)))
β는 reference 모델 이탈 강도 조절 하이퍼파라미터입니다. RLHF-PPO 대비 구현 복잡도가 낮고, reward hacking이 없습니다.
7. 변형·확장
- LoRA + SFT (QLoRA): 4-bit 양자화 + LoRA로 소비자 GPU(RTX 4090 24GB)에서 7B 모델 SFT 가능.
bitsandbytes+ PEFT 조합. - DPO 변형:
- IPO (Identity Preference Optimization): DPO의 과적합 문제를 정규화로 해결.
- KTO: chosen/rejected 쌍이 아닌 단일 응답에 binary 선호 레이블만 있어도 학습.
- SimPO: reference 모델 없이 길이 정규화 포함 단순화된 DPO.
- ORPO (Odds Ratio Preference Optimization): SFT와 선호도 학습을 단일 손실 함수로 통합. 별도 reference 모델 불필요.
8. 다른 도구·접근과의 비교 (3-way)
SFT vs RLHF vs DPO
| 항목 | SFT | RLHF | DPO |
|---|---|---|---|
| 데이터 | instruction + 정답 쌍 | 선호도 레이블(인간) | chosen/rejected 쌍 |
| 보상 모델 | 불필요 | 필요 (별도 학습) | 불필요 |
| 구현 복잡도 | 낮음 | 높음 (PPO+RM 2단계) | 중간 |
| GPU 비용 | 중간 | 높음 (모델 2개+) | 중간 (ref 모델 포함) |
| reward hacking | 없음 | 있음 (PPO 클리핑 필요) | 없음 |
TRL vs LLaMA-Factory vs Axolotl
| 항목 | TRL | LLaMA-Factory | Axolotl |
|---|---|---|---|
| 추상화 수준 | 중간 (Python API) | 높음 (YAML CLI) | 높음 (YAML config) |
| 지원 기법 | SFT/DPO/PPO/GRPO | SFT/DPO/RLHF/ORPO | SFT/QLoRA/Flash Attn |
| 커스터마이징 | 자유도 높음 | 설정 파일 중심 | 설정 파일 중심 |
Full FT vs LoRA vs QLoRA
| 항목 | Full Fine-Tuning | LoRA | QLoRA |
|---|---|---|---|
| VRAM (7B 기준) | ~112GB | ~24GB | ~8GB |
| 성능 | 최고 | Full FT 90%+ | LoRA와 유사 |
| 학습 속도 | 느림 | 빠름 | 중간 |
9. 한계·트레이드오프
- Compute·GPU 비용: RLHF-PPO는 policy 모델 + reference 모델 + reward 모델 등 최소 3개 모델을 동시에 메모리에 올려야 하므로 A100 80GB 4장 이상이 일반적입니다.
- Reward Hacking (RLHF 특유): 보상 모델이 근사(approximation)이므로, 모델이 보상 모델을 속이는 방향으로 과적합될 수 있습니다. 보상 모델의 분포 밖 프롬프트에서 특히 취약합니다.
- Data Quality 의존: SFT/DPO 모두 데이터 품질에 크게 의존합니다. 노이즈·편향이 있는 chosen/rejected 쌍은 정렬 방향을 왜곡합니다.
10. 최신 권장 패턴 (2026-05 기준)
(2026-05 기준, HuggingFace TRL 공식 문서·Rafailov 2023·Anthropic Constitutional AI 논문 출처)
- DPO/SimPO가 RLHF-PPO 대체 추세: HuggingFace TRL 공식 예제가 DPO 중심으로 재편. PPO는 RLHF 연구 목적 외 프로덕션 적용이 줄어드는 추세 (HuggingFace TRL Docs, https://huggingface.co/docs/trl).
- QLoRA + DPO 조합: 4-bit 양자화 + LoRA + DPO로 소비자 GPU(RTX 4090 단일)에서 7B 모델 선호도 정렬이 가능합니다. 논문: Dettmers et al. 2023 "QLoRA" (https://arxiv.org/abs/2305.14314).
- Synthetic preference data (Constitutional AI 패턴): 인간 레이블 없이 모델 자체가 chosen/rejected 쌍을 생성·필터링하는 방식. Anthropic Constitutional AI (https://arxiv.org/abs/2212.08073) 에서 원형을 제시.
11. 메타인지 자기평가
본인 코드/시스템에 적용 가능한지 검증하는 절차입니다.
Step 1 — 현재 상태 점검
nvidia-smi
python -c "import trl; print(trl.__version__)"
Step 2 — 적용 가능성 평가 - 조건 1: GPU VRAM 8GB+ → QLoRA+DPO 적용 가능 - 조건 2: GPU VRAM 24GB+ → LoRA+SFT 전체 적용 가능 - 조건 3: instruction 데이터 500건 이상 → SFT 시작 가능 (소량이면 Alpaca 혼합 권장) - 조건 4: chosen/rejected 쌍 1,000건 이상 → DPO 유효
Step 3 — 점진 적용
1. SFT 먼저 적용 → instruction-following 기반 확보
2. 소규모 chosen/rejected 쌍 구축 (LLM-as-judge 활용 가능) → DPO 실험
3. W&B 또는 TensorBoard로 rewards/chosen·rewards/rejected 모니터링
4. beta 조정 (0.1 → 0.05 → 0.2 순으로 실험)
5. vLLM으로 서빙 테스트 후 프로덕션 배포
참조 모델
| 출처 | 적용 측면 |
|---|---|
| HuggingFace TRL Docs (https://huggingface.co/docs/trl) | SFT/DPO/PPO API |
| HuggingFace Transformers Docs (https://huggingface.co/docs/transformers) | Tokenizer·Model·Trainer |
| Anthropic Constitutional AI 논문 (https://arxiv.org/abs/2212.08073) | RLHF 원형 |
| DPO 원논문 (Rafailov 2023, https://arxiv.org/abs/2305.18290) | DPO 수학 |
| InstructGPT 논문 (Ouyang 2022, https://arxiv.org/abs/2203.02155) | SFT+RLHF 통합 |
| QLoRA 논문 (Dettmers 2023, https://arxiv.org/abs/2305.14314) | 소비자 GPU 학습 |
클릭하거나 Space를 눌러 뒤집기